package com.fulinlin;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * redis通用工具
 * 多个教程捞出来的方法,有重复的,懒得去重了
 * @author Dong_Jia_Qi on 2022/1/16
 */
@Slf4j
@Component
public class RedisUtil {

    @Resource
    private ValueOperations<String,Object> valueOperations;

    @Resource
    private HashOperations<String, String, Object> hashOperations;

    @Resource
    private ListOperations<String, Object> listOperations;

    @Resource
    private SetOperations<String, Object> setOperations;

    @Resource
    private ZSetOperations<String, Object> zSetOperations;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    /**
     * 默认过期时长，单位：秒
     */
    public static final long DEFAULT_EXPIRE = 60 * 60 * 24;

    /**
     * 不设置过期时长
     */
    public static final long NOT_EXPIRE = -1;


    /**
     * 判断缓存中是否有对应的value
     *
     * @param key
     * @return
     */
    public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 重名名key，如果newKey已经存在，则newKey的原值被覆盖
     *
     * @param oldKey
     * @param newKey
     */
    public void renameKey(String oldKey, String newKey) {
        redisTemplate.rename(oldKey, newKey);
    }

    /**
     * newKey不存在时才重命名
     *
     * @param oldKey
     * @param newKey
     * @return 修改成功返回true
     */
    public boolean renameKeyNotExist(String oldKey, String newKey) {
        return redisTemplate.renameIfAbsent(oldKey, newKey);
    }

    /**
     * 删除key
     *
     * @param key
     */
    public void deleteKey(String key) {
        redisTemplate.delete(key);
    }

    /**
     * 删除多个key
     *
     * @param keys
     */
    public void deleteKey(String... keys) {
        Set<String> kSet = Stream.of(keys).map(k -> k).collect(Collectors.toSet());
        redisTemplate.delete(kSet);
    }

    /**
     * 删除Key的集合
     *
     * @param keys
     */
    public void deleteKey(Collection<String> keys) {
        Set<String> kSet = keys.stream().map(k -> k).collect(Collectors.toSet());
        redisTemplate.delete(kSet);
    }

    /**
     * 删除集合对象
     *
     * @param collection
     */
    public void deleteObject(Collection collection) {
        redisTemplate.delete(collection);
    }

    /**
     * 设置key的生命周期
     *
     * @param key
     * @param time
     * @param timeUnit
     */
    public void expireKey(String key, long time, TimeUnit timeUnit) {
        redisTemplate.expire(key, time, timeUnit);
    }

    /**
     * 指定key在指定的日期过期
     *
     * @param key
     * @param date
     */
    public void expireKeyAt(String key, Date date) {
        redisTemplate.expireAt(key, date);
    }

    /**
     * 查询key的生命周期
     *
     * @param key
     * @param timeUnit
     * @return
     */
    public long getKeyExpire(String key, TimeUnit timeUnit) {
        return redisTemplate.getExpire(key, timeUnit);
    }

    /**
     * 将key设置为永久有效
     *
     * @param key
     */
    public void persistKey(String key) {
        redisTemplate.persist(key);
    }


    /**
     * redis的key
     * 形式为：
     * 表名:主键名:主键值:列名
     *
     * @param tableName 表名
     * @param majorKey 主键名
     * @param majorKeyValue 主键值
     * @param column 列名
     * @return
     */
    public static String getKeyWithColumn(String tableName,String majorKey,String majorKeyValue,String column){
        StringBuffer buffer = new StringBuffer();
        buffer.append(tableName).append(":");
        buffer.append(majorKey).append(":");
        buffer.append(majorKeyValue).append(":");
        buffer.append(column);
        return buffer.toString();
    }
    /**
     * redis的key
     * 形式为：
     * 表名:主键名:主键值
     *
     * @param tableName 表名
     * @param majorKey 主键名
     * @param majorKeyValue 主键值
     * @return
     */
    public static String getKey(String tableName,String majorKey,String majorKeyValue){
        StringBuffer buffer = new StringBuffer();
        buffer.append(tableName).append(":");
        buffer.append(majorKey).append(":");
        buffer.append(majorKeyValue).append(":");
        return buffer.toString();
    }

    /**
     * 缓存基本的对象，Integer、String、实体类等
     *
     * @param redisKey   缓存的键值
     * @param redisValue 缓存的值
     */
    public void set(String redisKey, Object redisValue) {
        valueOperations.set( redisKey, redisValue);
    }
    /**
     * 写入缓存设置时效时间
     *
     * @param redisKey
     * @param redisValue
     * @return
     */
    public void set(final String redisKey, Object redisValue, Long expireTime) {
        valueOperations.set(redisKey, redisValue);
        redisTemplate.expire(redisKey, expireTime, TimeUnit.SECONDS);
    }
    /**
     * 缓存基本的对象，Integer、String、实体类等
     *
     * @param redisKey      缓存的键值
     * @param redisValue    缓存的值
     * @param timeout  时间
     * @param timeUnit 时间颗粒度
     * @return 缓存的对象
     */
    public void set(String redisKey, Object redisValue,Integer timeout, TimeUnit timeUnit) {
        valueOperations.set( redisKey, redisValue, timeout, timeUnit);
    }
    /**
     * 缓存基本的对象，Integer、String、实体类等
     *
     * @param key   缓存的键值
     * @param value 缓存的值
     * @return 缓存的对象
     */
    public ValueOperations<String, Object> setCacheObject(String key, Object value) {
        valueOperations.set(key, value);
        return valueOperations;
    }
    /**
     * 缓存基本的对象，Integer、String、实体类等
     *
     * @param key      缓存的键值
     * @param value    缓存的值
     * @param timeout  时间
     * @param timeUnit 时间颗粒度
     * @return 缓存的对象
     */
    public ValueOperations<String, Object> setCacheObject(String key, Object value, Integer timeout, TimeUnit timeUnit) {
        valueOperations.set(key, value, timeout, timeUnit);
        return valueOperations;
    }

    /**
     * 获得缓存的基本对象。
     *
     * @param key 缓存键值
     * @return 缓存键值对应的数据
     */
    public Object get(final String key) {
        return valueOperations.get(key);
    }

    /**
     * @description: 通过redisKey 批量(map)设置redisValue(hash)
     * @param: [redisKey, redisValue]
     * @return: void
     * @author: Xue 8
     * @date: 2019/2/14
     */
    public void setHashAll(String redisKey, Map<String,Object> redisValue){
        hashOperations.putAll(redisKey, redisValue);
    }

    /**
     * @description: 通过redisKey、hashKey、hashValue设置单个redisValue(hash)
     * @param: [redisKey, hashKey, hashValue]
     * @return: void
     * @author: Xue 8
     * @date: 2019/2/14
     */
    public void setHash(String redisKey, String hashKey, Object hashValue){
        hashOperations.put(redisKey, hashKey, hashValue);
    }
    /**
     * 缓存Map
     *
     * @param key
     * @param dataMap
     * @return
     */
    public HashOperations<String, String, Object> setCacheMap(String key, Map<String, Object> dataMap) {
        if (null != dataMap) {
            for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
                hashOperations.put(key, entry.getKey(), entry.getValue());
            }
        }
        return hashOperations;
    }

    /**
     * @description: 通过redisValue、hashKey获取hashValue
     * @param: [redisKey, hashKey]
     * @return: java.lang.Object
     * @author: Xue 8
     * @date: 2019/2/14
     */
    public Object getHashValue(String redisKey, Object hashKey){
        return hashOperations.get(redisKey, hashKey);
    }

    /**
     * @description: 通过redisKey获取hash
     * @param: [redisKey]
     * @return: java.util.Map<java.lang.String,java.lang.Object>
     * @author: Xue 8
     * @date: 2019/2/14
     */
    public Map<String, Object> getHash(String redisKey){
        return hashOperations.entries(redisKey);
    }

    /**
     * @description: 通过redisKey设置redisValue(List)
     * @param: [redisKey, redisValue]
     * @return: void
     * @author: Xue 8
     * @date: 2019/2/14
     */
    public void setList(String redisKey, List<Object> redisValue){
        listOperations.leftPushAll(redisKey, redisValue);
    }

    /**
     * 缓存List数据
     *
     * @param key      缓存的键值
     * @param dataList 待缓存的List数据
     * @return 缓存的对象
     */
    public ListOperations<String, Object> setCacheList(String key, List<Object> dataList) {

        if (null != dataList) {
            int size = dataList.size();
            for (Object o : dataList) {
                listOperations.leftPush( key, o);
            }
        }
        return listOperations;
    }

    /**
     * 获得缓存的list对象
     *
     * @param key 缓存的键值
     * @return 缓存键值对应的数据
     */
    public List<Object> getCacheList(String key) {
        List<Object> dataList = new ArrayList<>();

        Long size = listOperations.size(key);
        if (null != size) {
            for (int i = 0; i < size; i++) {
                dataList.add(listOperations.index(key, i));
            }
        }
        return dataList;
    }


    /**
     * 缓存Set
     *
     * @param key     缓存键值
     * @param dataSet 缓存的数据
     * @return 缓存数据的对象
     */
    public BoundSetOperations<String, Object> setCacheSet(String key, Set<Object> dataSet) {
        BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
        for (Object o : dataSet) {
            setOperation.add(o);
        }
        return setOperation;
    }

    /**
     * 获得缓存的set
     *
     * @param key
     * @return
     */
    public Set<Object> getCacheSet(String key) {
        Set<Object> dataSet = new HashSet<>();
        BoundSetOperations<String, Object> operation = redisTemplate.boundSetOps(key);
        dataSet = operation.members();
        return dataSet;
    }

    /**
     * 获得缓存的Map
     *
     * @param key
     * @return
     */
    public Map<String, Object> getCacheMap(String key) {
        Map<String, Object> map = hashOperations.entries(key);
        return map;
    }

    /**
     * 获得缓存的基本对象列表
     *
     * @param pattern 字符串前缀
     * @return 对象列表
     */
    public Collection<String> keys(String pattern) {
        return redisTemplate.keys(pattern);
    }

    /**
     * 写入缓存
     *
     * @param key
     * @param offset   位 8Bit=1Byte
     * @return
     */
    public boolean setBit(String key, long offset, boolean isShow) {
        boolean result = false;
        try {
            valueOperations.setBit(key, offset, isShow);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 获得缓存
     *
     * @param key
     * @param offset
     * @return
     */
    public boolean getBit(String key, long offset) {
        boolean result = false;
        try {
            result = valueOperations.getBit(key, offset);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 批量删除对应的value
     *
     * @param keys
     */
    public void remove(final String... keys) {
        for (String key : keys) {
            remove(key);
        }
    }

    /**
     * 删除对应的value
     *
     * @param key
     */
    public void remove(final String key) {
        if (exists(key)) {
            redisTemplate.delete(key);
        }
    }

    /**
     * 哈希 添加
     *
     * @param key
     * @param hashKey
     * @param value
     */
    public void hmSet(String key, String hashKey, Object value) {
        log.info("key " +key +" hashKey " +hashKey);
        hashOperations.put(key, hashKey, value);
    }

    /**
     * 哈希获取数据
     *
     * @param key
     * @param hashKey
     * @return
     */
    public Object hmGet(String key, Object hashKey) {
        return hashOperations.get(key, hashKey);
    }

    /**
     * 哈希获得键的全部值
     * @param key
     * @return
     */
    public Set<String> hmGetAll(String key){
        return hashOperations.keys(key);
    }

    /**
     * 哈希删除键的某个值
     * @param key
     * @param hashKey
     * @return
     */
    public Long hmRemoveByKey(String key, Object hashKey){
        return hashOperations.delete(key, hashKey);
    }

    /**
     * 列表添加
     *
     * @param k
     * @param v
     */
    public void lPush(String k, Object v) {
        listOperations.rightPush(k, v);
    }

    /**
     * 列表获取
     *
     * @param k
     * @param l
     * @param l1
     * @return
     */
    public List<Object> lRange(String k, long l, long l1) {
        return listOperations.range(k, l, l1);
    }

    /**
     * 集合添加
     *
     * @param key
     * @param value
     */
    public void add(String key, Object value) {
        setOperations.add(key, value);
    }

    /**
     * 集合获取
     *
     * @param key
     * @return
     */
    public Set<Object> setMembers(String key) {
        return setOperations.members(key);
    }

    /**
     * 判断set中是否存在值
     * @param key
     * @param value
     * @return
     */
    public boolean setIsMember(String key ,Object value){
        return setOperations.isMember(key,value);
    }
    /**
     * 有序集合添加
     *
     * @param key
     * @param value
     * @param scoure
     */
    public void zAdd(String key, Object value, double scoure) {
        zSetOperations.add(key, value, scoure);
    }

    /**
     * 有序集合获取
     *
     * @param key
     * @param scoure
     * @param scoure1
     * @return
     */
    public Set<Object> rangeByScore(String key, double scoure, double scoure1) {
        return zSetOperations.rangeByScore(key, scoure, scoure1);
    }



    /**
     * 有序集合获取排名
     *
     * @param key 集合名称
     * @param value 值
     */
    public Long zRank(String key, Object value) {
        return zSetOperations.rank(key,value);
    }


    /**
     * 有序集合获取排名
     *
     * @param key
     */
    public Set<ZSetOperations.TypedTuple<Object>> zRankWithScore(String key, long start,long end) {
        Set<ZSetOperations.TypedTuple<Object>> ret = zSetOperations.rangeWithScores(key,start,end);
        return ret;
    }

    /**
     * 有序集合添加
     *
     * @param key
     * @param value
     */
    public Double zSetScore(String key, Object value) {
        return zSetOperations.score(key,value);
    }


    /**
     * 有序集合添加分数
     *
     * @param key
     * @param value
     * @param scoure
     */
    public void incrementScore(String key, Object value, double scoure) {
        zSetOperations.incrementScore(key, value, scoure);
    }


    /**
     * 有序集合获取排名
     *
     * @param key
     */
    public Set<ZSetOperations.TypedTuple<Object>> reverseZRankWithScore(String key, long start,long end) {
        Set<ZSetOperations.TypedTuple<Object>> ret = zSetOperations.reverseRangeByScoreWithScores(key,start,end);
        return ret;
    }

    /**
     * 有序集合获取排名
     *
     * @param key
     */
    public Set<ZSetOperations.TypedTuple<Object>> reverseZRankWithRank(String key, long start, long end) {
        Set<ZSetOperations.TypedTuple<Object>> ret = zSetOperations.reverseRangeWithScores(key, start, end);
        return ret;
    }

}
